<template>
  <a-select
    style="width: 100%"
    :disabled="disabled"
    :placeholder="placeholder"
    :allowClear="allowClear"
    v-bind="uiAttr"
    :mode="multiple ? 'multiple' : ''"
    :filterOption="false"
    :value="modelValue"
    @search="handleSearch"
    @change="handleChange"
    :notFoundContent="loading ? undefined : null"
  >
    <a-spin v-if="loading" slot="notFoundContent" size="small" />
    <a-select-option v-for="item in options" :key="item.value" :value="item.value" :title="item.text">{{
      item.text
    }}</a-select-option>
  </a-select>
</template>

<script>
import { getAction } from '../../api/manage'
import { simpleDebounce } from '@/utils/util'

/**
 * 通过接口参数变化远程检索获取下拉内容的组件
 * 注意：
 * @input value 支持v-model，第一个参数未选中时向外传递undefined,如果是多选，接收和传递的是一个逗号分割的字符串，第二个参数是旧值,第三个参数是选中值包含key和value的对象数组
 */
export default {
  props: {
    value: [String, Number], //支持v-model，未选中时向外传递undefined,如果是多选，接收和传递的是一个逗号分割的字符串
    // 请求的地址，必传，如果需要额外参数可以写成 xxx?sex=1&name=2...
    url: {
      type: String,
      required: true,
    },
    // 搜索字段
    queryWord: {
      type: String,
      default: 'name',
    },
    // option使用的value,如果需要回显则必传，回显的时候optionValue会临时替换掉queryWord
    optionValue: {
      type: String,
      default: 'id',
    },
    // option使用的label
    optionLabel: {
      type: String,
      default: 'name',
    },
    // 自定义option(有此参数optionValue，optionLabel配置项将失效)，入参是请求接口获取的result，返回值接收一个至少包含value和text的数组对象用于渲染option
    optionDiy: {
      type: Function,
    },
    // 是否支持多选
    multiple: {
      type: Boolean,
      default: false,
    },
    // 内容提示
    placeholder: {
      type: String,
      default: '请搜索并选择',
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 是否可以清除
    allowClear: {
      type: Boolean,
      default: true,
    },
    // 下拉原则器原生配置项会与默认当前组件uiAttr默认配置进行合并,ui效果，禁用效果等 https://www.antdv.com/components/select-cn
    uiProps: {
      type: Object,
      default: () => {},
    },
  },
  model: {
    prop: 'value',
    event: 'change',
  },
  data() {
    return {
      loading: false,
      modelValue: undefined,
      options: [], // 下拉列表
      uiAttr: {
        showSearch: true,
        maxTagCount: 1,
      },
    }
  },
  watch: {
    value: {
      immediate: true,
      handler(val) {
        const strModelValue = Array.isArray(this.modelValue) ? this.modelValue.join(',') : this.modelValue
        if (val !== strModelValue) {
          // 处理回显及父组件变动时加载list
          this.loadOptions(this.value, true)
        }
        if (this.multiple) {
          this.modelValue = val ? String(val).split(',') : []
        } else {
          this.modelValue = val ? val : undefined //处理值为空字符串时placeholder不显示问题
        }
      },
    },
    uiProps: {
      immediate: true,
      deep: true,
      handler(val) {
        this.uiAttr = { ...this.uiAttr, ...val }
      },
    },
  },
  created() {
    this.loadOptions()
  },
  methods: {
    //  加载字典数据
    loadOptions(value, isValue) {
      if (value) {
        this.loading = true
        let params = {}
        if (isValue) {
          params = { [this.optionValue]: value }
        } else {
          params = { [this.queryWord]: value }
        }
        getAction(this.url, params).then((res) => {
          this.loading = false
          if (res.success) {
            if (this.optionDiy) {
              this.options = this.optionDiy(res.result)
            } else {
              this.options = res.result.map((i) => ({
                ...i,
                value: typeof i === 'object' && i !== null ? i[this.optionValue] : i,
                text: typeof i === 'object' && i !== null ? i[this.optionLabel] : i,
              }))
            }
          } else {
            this.$message.warning(res.message)
          }
        })
      }
    },
    // 搜索动作
    handleSearch: simpleDebounce(function (value) {
      this.loadOptions(value)
    }, 400),
    //选中动作
    handleChange(selectedValue) {
      let oldValue = this.modelValue
      this.modelValue = selectedValue
      if (this.multiple) {
        if (selectedValue.length === 0) {
          this.$emit('change', undefined, oldValue, [])
        } else {
          this.$emit(
            'change',
            selectedValue.length > 1 ? selectedValue.join(',') : selectedValue[0],
            oldValue,
            this.options.filter((i1) => selectedValue.includes(i1.value))
          )
        }
      } else {
        this.$emit(
          'change',
          selectedValue,
          oldValue,
          this.options.find((i) => i.value === selectedValue)
        )
      }
    },
  },
}
</script>
